package no.sachmuld.methodcombination.examples.reflection.combo;

import no.sachmuld.methodcombination.api.BehaviourChain;
import no.sachmuld.methodcombination.api.CrosscuttingBehaviour;
import no.sachmuld.methodcombination.api.Direction;
import no.sachmuld.methodcombination.api.reflection.component.SimpleMethodCombination;
import no.sachmuld.methodcombination.api.reflection.component.*;

import java.lang.reflect.Method;

/**
 *
 */
public class SimpleCrosscutting<B extends CrosscuttingBehaviour, R> extends DelegatingMethodCombination<B, R> {

    private SimpleMethodCombination simpleMethodCombination;

    public SimpleCrosscutting() {
    }

    public SimpleCrosscutting(SimpleMethodCombination simpleMethodCombination) {
        this.simpleMethodCombination = simpleMethodCombination;
    }

    public void setSimpleMethodCombination(SimpleMethodCombination simpleMethodCombination) {
        this.simpleMethodCombination = simpleMethodCombination;
    }

    @Override
    public SimpleCrosscutting<B, R> build(final Class behaviourClass, final Method targetMethod) {

        final Direction direction = Direction.BOTTOM_UP;

        final CrosscuttingAroundMethodCombination<B, R> crosscuttingAround = new CrosscuttingAroundMethodCombination<>();
        final AroundMethodCombination<B, R>             around = new AroundMethodCombination<>(targetMethod.getName(), direction);
        final CrosscuttingBeforeMethodCombination       crosscuttingBefore = new CrosscuttingBeforeMethodCombination();
        final CrosscuttingAfterMethodCombination        crosscuttingAfter = new CrosscuttingAfterMethodCombination();

        simpleMethodCombination.setDisableAroundMethods(true);

        buildChildren(behaviourClass, targetMethod, crosscuttingAround, around, crosscuttingBefore, crosscuttingAfter, simpleMethodCombination);

        executedBy(
                crosscuttingAround.inner(
                        around.inner(
                                new AbstractMethodCombination<B, R>() {

                                    @Override
                                    public R execute(final Object targetObject, BehaviourChain<? extends B> behaviourChain, final Object... parameters) {

                                        crosscuttingBefore.execute(targetObject, behaviourChain, parameters);

                                        R result = (R) simpleMethodCombination.execute(targetObject, behaviourChain, parameters);

                                        crosscuttingAfter.execute(targetObject, behaviourChain, parameters);

                                        return result;
                                    }
                                })));

        return this;

    }

}
